import java.awt.Graphics2D;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;

public class StraightArrow extends Arrow {
	private final Line2D.Double baseLine = new Line2D.Double();
	private final ArrowHead arrowHead;
	private final CubicCurve2D baseCurve = new CubicCurve2D.Double();

	public StraightArrow(Quiver quiver, Node fromNode, Node toNode) {
		super(quiver, fromNode, toNode);
		arrowHead = new ArrowHead(config, this);
		setName();
		update();
	}

	public void update() {
		fromPoint.setLocation(fromNode.getPoint());
		toPoint.setLocation(toNode.getPoint());
		double length = fromPoint.distance(toPoint)/2;
		fromAngle = Math.atan2(toPoint.getY() - fromPoint.getY(),
				toPoint.getX() - fromPoint.getX());
		toAngle = fromAngle;

		if (isBidirectional) {
			double bentArrowAngle = (90/(1 + Math.pow(length,2)*0.0001))*Math.PI/180;
			fromAngle += bentArrowAngle/2;
			toAngle -= bentArrowAngle/2;
		}

		// adjust for radius of nodes
		fromPoint.setLocation(fromPoint.getX() + config.visibleNodeRadius
				* Math.cos(fromAngle), fromPoint.getY()
				+ config.visibleNodeRadius * Math.sin(fromAngle));
		toPoint.setLocation(toPoint.getX() - config.visibleNodeRadius
				* Math.cos(toAngle), toPoint.getY() - config.visibleNodeRadius
				* Math.sin(toAngle));

		if (isBidirectional) {
			length /= 2;
			Point2D.Double cp1 = new Point2D.Double(fromPoint.getX() + length
					* Math.cos(fromAngle), fromPoint.getY() + length
					* Math.sin(fromAngle));
			Point2D.Double cp2 = new Point2D.Double(toPoint.getX() + length
					* Math.cos(toAngle + Math.PI), toPoint.getY() + length
					* Math.sin(toAngle + Math.PI));
			baseCurve.setCurve(fromPoint, cp1, cp2, toPoint);
		} else {
			baseLine.setLine(fromPoint, toPoint);
		}
		arrowHead.update();
	}

	@Override
	public Point2D getMidpoint() {
		return new Point2D.Double(0.5 * (fromPoint.getX() + toPoint.getX()),
				0.5 * (fromPoint.getY() + toPoint.getY()));
	}

	@Override
	public void paint(Graphics2D g) {
		g.setPaint(config.arrowColor);
		arrowHead.paint(g);
		if (isBidirectional) {
			g.draw(baseCurve);
		} else {
			g.draw(baseLine);
		}
		if (config.showLabels) {
			paintLabel(g);
		}
	}

	@Override
	public boolean isClose(Point2D point) {
		return baseLine.ptSegDist(point) <= config.arrowWidth / 2;
	}
}
